import { CameraAnimation } from "./CameraAnimation";
import { ContainerHost } from "../../Container";
import { ViewerService } from "../ViewerService";

export interface IAnimation { name: string, frames: IAnimationFrame[] };
export interface IAnimationFrame { name: string, state: { viewport: { eye: number[], target: number[] } }, time: number };
/**
 * 播放器
 */
export class AnimationPlayer {

    CurrentTimeChanged?: (ms?: number) => void;
    private currentAnimation: CameraAnimation = new CameraAnimation();
    private currentRAFId!: number;
    private playMode: "play" | "loop-play" = "play";
    private isPlaying: boolean = false;
    private clock: THREE.Clock | undefined = undefined;
    private deltaTimeMs: number = 0;
    private playMultiSpeed: number = 1;
    private minDeltaFrameTimeMs = 32;
    private viewer: Sippreep.Viewing.Viewer3D | undefined;
    private totalTimeMs: number = 0;
    private currentAnimationTimeMs: number = 0;
    setPlayModeNormalPlay() {
        this.playMode = 'play'
    }
    setPlayModeLoopPlay() {
        this.playMode = 'loop-play';
    }
    setCurrentAnimation(anim: CameraAnimation = new CameraAnimation()) {
        this.currentAnimation = anim;
    }
    setAnimationData(data: IAnimation) {
        this.currentAnimation = new CameraAnimation().setFramesData(data);
    }
    /**
     * 要么传入CameraAnimation，要么之前setCurrentAnimation
     * @param anim
     * @returns
     */
    play(anim?: CameraAnimation): AnimationPlayer {
        this.currentAnimation = anim ?? this.currentAnimation;
        if (this.isPlaying) {
            return this;
        }
        this.totalTimeMs = this.currentAnimation.getTotalTime();
        this.isPlaying = true;
        this.clock = new THREE.Clock(true);
        ContainerHost.Current.Get(ViewerService).ViewerPromise.then(v => {
            this.viewer = v;
            this.currentRAFId = requestAnimationFrame(this.thisAnimLoop);
        });

        return this;
    }
    pause() {
        if (this.isPlaying) {
            this.isPlaying = false;
        }
    }
    stop() {
        if (this.isPlaying) {
            this.isPlaying = false;
        }
        if (this.currentRAFId) {
            cancelAnimationFrame(this.currentRAFId);
        }
        this.currentAnimationTimeMs = 0;
    }

    thisAnimLoop = () => this.animLoop();
    private animLoop() {
        if (!this.isPlaying) {
            return;
        }
        if (!this.clock) {
            return;
        }
        this.deltaTimeMs += this.clock.getDelta() * 1000;
        if (this.deltaTimeMs > this.minDeltaFrameTimeMs) {
            this.render();
            this.deltaTimeMs = 0;
        }
        this.currentRAFId = requestAnimationFrame(this.thisAnimLoop);
    }
    private render() {
        if (this.currentAnimationTimeMs >= this.totalTimeMs) {
            this.currentAnimationTimeMs = 0;
            if (this.playMode == "play") {
                this.isPlaying = false;
                cancelAnimationFrame(this.currentRAFId);
            }
            return;
        }
        this.deltaTimeMs *= this.playMultiSpeed;
        this.currentAnimationTimeMs += this.deltaTimeMs;
        this.currentAnimation.update(this.currentAnimationTimeMs, this.viewer!);
        if (this.CurrentTimeChanged) {
            this.CurrentTimeChanged(this.currentAnimationTimeMs);
        }
    }
    /**
     * 返回0~1的播放进度
     * @returns
     */
    getPlaybackProgress(): number {
        if (this.getTotalTimeMs() == 0) {
            return 0;
        }
        let process = Math.min(1, this.currentAnimationTimeMs / this.totalTimeMs);
        process = Math.max(0, process);
        return process;
    }
    setTotalTimeSpliteByDistance(ms: number) {
        if (!this.currentAnimation) {
            return;
        }
        this.currentAnimation.setTotalTimeSpliteByDistance(ms);
    }
    setTotalTimeSpliteByFrame(ms: number) {
        if (!this.currentAnimation) {
            return;
        }
        this.currentAnimation.setTotalTimeSpliteByFrame(ms);
    }
    getTotalTimeMs(): number {
        if (!this.currentAnimation) {
            return 0;
        }
        this.totalTimeMs = this.currentAnimation.getTotalTime();
        return this.totalTimeMs;
    }
    getPlayMultiSpeed(): number {
        return this.playMultiSpeed;
    }
    setPlayMultiSpeed1X() {
        this.playMultiSpeed = 1;
    }
    setPlayMultiSpeed2X() {
        this.playMultiSpeed = 2;
    }
    setPlayMultiSpeed4X() {
        this.playMultiSpeed = 4;
    }
    setPlayMultiSpeed16X() {
        this.playMultiSpeed = 16;
    }
    setAnimationTime(v: number) {
        this.currentAnimationTimeMs = v;
        this.currentAnimation.update(this.currentAnimationTimeMs, this.viewer!);
        if (this.CurrentTimeChanged) {
            this.CurrentTimeChanged(this.currentAnimationTimeMs);
        }
    }
    getAnimationTime(): number {
        return this.currentAnimationTimeMs;
    }
    setAnimationProgress(progress: number) {
        progress = Math.min(1, progress);
        progress = Math.max(0, progress);
        this.setAnimationTime(progress * this.totalTimeMs);
    }
}
